﻿module TrashMan

open System
open System.Collections.Generic
open System.Linq
open System.Text.RegularExpressions
open Microsoft.FSharp.Collections
open Microsoft.Xna.Framework
open Microsoft.Xna.Framework.Audio
open Microsoft.Xna.Framework.Content
open Microsoft.Xna.Framework.GamerServices
open Microsoft.Xna.Framework.Graphics
open Microsoft.Xna.Framework.Input
open Microsoft.Xna.Framework.Media
open EntitiesAndGameState
open Component
open UnfoldMonad
open Services
open Utils
open AudioComponent
open TutorialStr

let manage_emenies () = 
  unfold { 
    let random = new Random()
    do! forever_ 
          (unfold {
            let! level = use_level (fun level -> unfold { return level } )
            let! state = use_state (fun state -> unfold { return state } )
            let time_to_next_spawn = 
              ((-Math.Atan(float level / 3.0 - 1.0) + float MathHelper.PiOver2) + (random.NextDouble()) * (-Math.Atan(float level / 3.0 - 1.0) + float MathHelper.PiOver2)) |> float32

            do! wait time_to_next_spawn

            let difficulty = ref ((float32) level / 15.0f)

            if !difficulty > 1.0f then difficulty := 1.0f
            else difficulty := 0.0f

            let start_dest = UtilsWAG.generateStartDestinationPoints(!difficulty,random)
            let enemie_type_to_add = enum<GarbageType>(random.Next(0, 6))
            let enemie = new ShipToAdd(start_dest.[0],start_dest.[1],true,0.0f,enemie_type_to_add,true,false)

            do! add_enemie enemie
          })
    }

let manage_garbages () = 
  unfold { 
    let random = new Random()
    do! forever_ 
          (unfold {
            do! wait 2.0f
            let! level = use_level (fun level -> unfold { return level } )
            let! garbage_sac = get_garbage_sac
            let! state = use_state (fun state -> unfold { return state } )

            if garbage_sac.Count < Math.Min(6, level) then
              let garbage_sac = new GarbageSacToAdd()
              garbage_sac.DimMin <- 100
              garbage_sac.DimMax <- 200
              garbage_sac.Vel <- level

              UtilsWAG.add_garbage_sac(state,garbage_sac)
          })
    }

let manage_earth_life () = 
  unfold {     
    do! forever_ 
          (unfold {
            do! wait 10.0f
            Background.EarthLife <- Math.Min(Background.EarthLife + 1,Background.MAX_EARTH_LIFE)
          })
    }
let manage_trash_bins (audioManager:IAudioManager) = 
  unfold {     
    do! forever_ 
          (unfold {
            let! state = use_state (fun state -> unfold { return state } )
            do! parallel_many_
                  [ (forever_
                        (unfold{
                            let! state = use_state (fun state -> unfold { return state } )
                            if state.YellowTrashBinState >= State.MAX_YELLOW_TRASH_BIN_CAPACITY then
                              do audioManager.OnTrashMaster(4.f)
                              do! use_state (fun state -> unfold { 
                                                            state.num_of_bubble_wave <- state.num_of_bubble_wave + 1
                                                            state.yellow_trash_unloading_animation <- State.TRASH_UNLOADING_ANIMATION_TIME
                                                            state.YellowTrashBinState <- 0 })
                          }));
                    (forever_
                        (unfold{
                            let! state = use_state (fun state -> unfold { return state } )
                            if state.GreenTrashBinState >= State.MAX_GREEN_TRASH_BIN_CAPACITY then
                              do audioManager.OnTrashMaster(4.f)
                              do! use_state (fun state -> unfold { 
                                                            state.num_of_bubble_wave <- state.num_of_bubble_wave + 1
                                                            state.green_trash_unloading_animation <- State.TRASH_UNLOADING_ANIMATION_TIME
                                                            state.GreenTrashBinState <- 0 })
                          }));
                    (forever_
                        (unfold{
                            let! state = use_state (fun state -> unfold { return state } )
                            if state.BlueTrashBinState >= State.MAX_BLUE_TRASH_BIN_CAPACITY then
                              do audioManager.OnTrashMaster(4.f)
                              do! use_state (fun state -> unfold { 
                                                            state.num_of_bubble_wave <- state.num_of_bubble_wave + 1
                                                            state.blue_trash_unloading_animation <- State.TRASH_UNLOADING_ANIMATION_TIME
                                                            state.BlueTrashBinState <- 0 })
                          }));]
//                    (forever_
//                        (unfold{
//                            let! state = use_state (fun state -> unfold { return state } )
//                            if state.ManHoleState >= int State.MAN_HOLE_CAPACITY then
//                              do! use_state (fun state -> unfold { 
//                                                            state.ManHoleState <- 0 })
//                          })) ]
          })
    }

let check_defeat () = 
  unfold{
    do! wait_while_
          (unfold{
              let! state = use_state (fun s -> unfold {return s})              
              if state.EarthLife <= 0 then return false
              else return true
          })
  }

let test_zoom () =
  unfold{
    do! wait 10.0f

    let! enemie = get_garbage 0
    let! state = use_state (fun state -> unfold { return state } )

    let source_start : Vector3 = state.bounding_sphere.Center
    let source_rage : float32 = state.bounding_sphere.Radius

    //let dest_start : Vector3 = Vector3(enemie.geometry.Position.X , enemie.geometry.Position.Y, enemie.geometry.Position.Z)
    let dest_start : Vector3 = enemie.geometry.Position;    
    let dest_rage : float32 = zoom_enemie_rage

    do! use_state (fun s -> unfold{ s.IsZoomed <- true })
    do! zoom_in 2.0f source_start source_rage dest_start dest_rage
    do! wait 3.0f
    
    do! use_state (fun s -> unfold{ s.IsZoomed <- false })
    do! zoom_out 2.0f
  }
let update_level () =
  unfold{
    do! forever_
            (unfold{
              do! update_time_to_next_level
              let! state = use_state (fun s -> unfold { return s })
              do! use_level (fun l -> unfold { 
                                          if state.time_to_next_level < 0.0f then
                                            do! inc_level
                                            let! state = use_state (fun s -> unfold { return s })
                                            do! set_time_to_next_level (State.TIME_FOR_LEVEL + ((float32) state.level) * 5.0f)})
             })
  }
let game_logic (audioManager:IAudioManager) =
  unfold{
    do! parallel_many_
          [ manage_emenies ();
            manage_garbages ();
            manage_trash_bins (audioManager);
            manage_earth_life ();
            update_level()]
            //test_zoom ()]
    
    return true
  }

let trashMan (game:Game) (strings:TutorialStrings) : Script<GameResult> = 
  let am = (game.Services.GetService(typeof<IAudioManager>)) 
  let audioManager = am :?> IAudioManager
  unfold{    
    do! parallel_first_
          (game_logic (audioManager))
          (check_defeat ()) |> ignore_
    return EntitiesAndGameState.GameState.Defeat
  }
